﻿using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Configuration;
using System.Data.SqlClient;

namespace OnlinePaymentService
{

    /// <summary>
    /// Summary description for Service1
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [ToolboxItem(false)]
    // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
    // [System.Web.Script.Services.ScriptService]
    public class Service09 : System.Web.Services.WebService
    {
        #region Constants
        const string OK = "OK";
        const string PHONE_NOT_FOUND = "Phone not found";
        const string TRANSACTION_ALLREADY_EXISTS = "Transaction already exists";
        const string SQL_EXCEPTION = "SQL exception";
        const string UNKNOWN_ERROR = "Unknown Error";
        const string INVALID_AMOUNT = "Invalid amount";
        const string INVALID_MD5 = "Invalid MD5";
        const string PAYMENT_IMPOSSIBLE = "Payment, impossible on this phone.";
        #endregion

        #region WebMethods
        [WebMethod]
        public GetInfoResult GetInfo(string Number, string MD5)
        {
            GetInfoResult Result = new GetInfoResult(Number);
            SetError(Result, -4);
            try
            {
                if (this.GetMD5(Number, this.GetMD5Key()) != MD5)
                    throw new InvalidMD5();

                int ReturnCode;
                string Name = string.Empty;
                string Address = string.Empty;
                decimal? Balance = null;
                BillingDataContext bc = new BillingDataContext();

                ReturnCode = bc.AccountInfoSelect(Number, ref Name, ref Address, ref Balance);

                if (ReturnCode == 0)
                {
                    SetError(Result, 0);
                    Result.Name = Name;
                    Result.Address = Address;
                    if (Balance.HasValue)
                        Result.Balance = Balance.Value;
                    else
                        Result.Balance = 0;
                }
                if (ReturnCode == -1)
                    SetError(Result, -1);
                if (ReturnCode == -7)
                    SetError(Result, -7);
            }
            catch (SqlException)
            { SetError(Result, -3); }
            catch (InvalidAmountException)
            { SetError(Result, -5); }
            catch (InvalidMD5)
            { SetError(Result, -6); }
            catch (Exception)
            { SetError(Result, -4); }
            return Result;
        }
        [WebMethod]
        public PayResult Pay(string Number, DateTime PaymentDate, int Amount, long ForeignPaymentID, string MD5)
        {

            PayResult Result = new PayResult(Number);
            SetError(Result, -4);
            try
            {
                if (this.GetMD5(Number, this.GetMD5Key()) != MD5)
                    throw new InvalidMD5();

                int ReturnCode;
                decimal am = 0;
                long? ID = null;

                if (Amount == 0 || Amount < 0)
                {
                    SetError(Result, -5);
                    throw new InvalidAmountException();
                }


                BillingDataContext bc = new BillingDataContext();



                am = (decimal)Amount / 100;

                ReturnCode = bc.BankPaymentAdd(
                    ref ID,
                    Number,
                    PaymentDate,
                    am,
                    ForeignPaymentID,
                    this.GetPaymentPointID(),
                    this.Context.Request.UserHostAddress);


                if (ReturnCode == 0)
                {
                    Result.PaymentID = ID.Value;
                    SetError(Result, 0);
                }
                if (ReturnCode == -1)
                    SetError(Result, -1);
                if (ReturnCode == -7)
                    SetError(Result, -7);
                if (ReturnCode == -2)
                    SetError(Result, -2);
            }
            catch (SqlException)
            { SetError(Result, -3); }
            catch (InvalidAmountException)
            { SetError(Result, -5); }
            catch (InvalidMD5)
            { SetError(Result, -6); }
            catch (Exception)
            { SetError(Result, -4); }
            return Result;
        }
        [WebMethod]
        public string GetMD5(string Number, string Key)
        {
            MD5 md5 = MD5.Create();
            return BitConverter.ToString(md5.ComputeHash(Encoding.ASCII.GetBytes(string.Concat(Number, Key)))).Replace("-", null);
        }
        #endregion

        #region PrivateMethods
        private void SetError(BaseResult Result, int ErrorCode)
        {
            Result.ErrorCode = ErrorCode;
            switch (ErrorCode)
            {
                case 0:
                    Result.ErrorDescription = OK;
                    break;
                case -1:
                    Result.ErrorDescription = PHONE_NOT_FOUND;
                    break;
                case -2:
                    Result.ErrorDescription = TRANSACTION_ALLREADY_EXISTS;
                    break;
                case -3:
                    Result.ErrorDescription = SQL_EXCEPTION;
                    break;
                case -4:
                    Result.ErrorDescription = UNKNOWN_ERROR;
                    break;
                case -5:
                    Result.ErrorDescription = INVALID_AMOUNT;
                    break;
                case -6:
                    Result.ErrorDescription = INVALID_MD5;
                    break;
                case -7:
                    Result.ErrorDescription = PAYMENT_IMPOSSIBLE;
                    break;
                default:
                    break;
            }

        }
        private string GetMD5Key()
        {
            return ConfigurationManager.AppSettings["MD5KEY"];
        }
        private short GetPaymentPointID()
        {
            return Convert.ToInt16(ConfigurationManager.AppSettings["PaymentPointID"]);
        }
        #endregion
    }
    #region ResultClases
    public class BaseResult
    {
        private string mErrorDescription;
        public string ErrorDescription
        {
            get { return mErrorDescription; }
            set { mErrorDescription = value; }
        }

        private int mErrorCode;
        public int ErrorCode
        {
            get { return mErrorCode; }
            set { mErrorCode = value; }
        }
    }
    public class GetInfoResult : BaseResult
    {
        public GetInfoResult()
        { }
        public GetInfoResult(string number)
        {
            mNumber = number;
        }

        private string mNumber;
        public string Number
        {
            get { return mNumber; }
            set { mNumber = value; }
        }

        private string mName;
        public string Name
        {
            get { return mName; }
            set { mName = value; }
        }

        private string mAddress;
        public string Address
        {
            get { return mAddress; }
            set { mAddress = value; }
        }

        private decimal mBalance;
        public decimal Balance
        {
            get { return mBalance; }
            set { mBalance = value; }
        }

        private string mMD5;
        public string MD5
        {
            get { return mMD5; }
            set { mMD5 = value; }
        }
    }
    public class PayResult : BaseResult
    {
        public PayResult()
        { }
        public PayResult(string number)
        {
            mNumber = number;
        }

        private string mNumber;
        public string Number
        {
            get { return mNumber; }
        }

        private long mPaymentID;
        public long PaymentID
        {
            get { return mPaymentID; }
            set { mPaymentID = value; }
        }

        private string mMD5;
        public string MD5
        {
            get { return mMD5; }
            set { mMD5 = value; }
        }
    }
    #endregion
}
